global temperature_asm

section .data
mask: db 0x00, 0x01, 0x02, 0xFF, 0x03, 0x04, 0x05, 0xFF, 0x06,0x07,0x08,0xFF, 0x09,0x0A,0x0B,0xFF
muchos_unos: db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
borrarfruta: db 255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0
caso1: db 128,0,0,0,128,0,0,0,128,0,0,0,128,0,0,0
caso2: db 255,0,0,0,255,0,0,0,255,0,0,0,255,0,0,0
caso3: db 255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0
caso4: db 0,255,255,0,0,255,255,0, 0,255,255,0, 0,255,255,0
caso5: db 0,0,255,0,0,0,255,0,0,0,255,0,0,0,255,0
tres: dd 3, 3, 3, 3
mask32: dd 32, 32, 32, 32
mask96: dd 96, 96, 96, 96
mask128: dd 128,128,128,128
mask160: dd 160, 160, 160, 160
mask224: dd 224, 224, 224, 224
a43bytes: db 0x00,0x01,0x02,0x04,0x05,0x06,0x08,0x09,0x0a,0x0c,0x0d,0x0e,0xFF,0xFF,0xFF,0xFF
mask_temp1: db 0x00,0xFF,0xFF,0xFF,0x01,0xFF,0xFF,0xFF,0x02,0xFF,0xFF,0xFF,0x03,0xFF,0xFF,0xFF
mask_temp2: db 0xFF,0x00,0xFF,0xFF,0xFF,0x01,0xFF,0xFF,0xFF,0x02,0xFF,0xFF,0xFF,0x03,0xFF,0xFF
mask_temp3: db 0xFF,0xFF,0x00,0xFF,0xFF,0xFF,0x01,0xFF,0xFF,0xFF,0x02,0xFF,0xFF,0xFF,0x03,0xFF
mask_temp4: db 0xFF,0x00,0xFF,0xFF,0xFF,0x01,0xFF,0xFF,0xFF,0x02,0xFF,0xFF,0xFF,0x03,0xFF,0xFF
mask_temp5: db 0xFF,0xFF,0x00,0xFF,0xFF,0xFF,0x01,0xFF,0xFF,0xFF,0x02,0xFF,0xFF,0xFF,0x03,0xFF
mask_padd1: db 0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
mask_padd2: db 0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
padd_1: db 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00
padd_2: db 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
mask_dest: db 0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00

%define i r10
%define j r11
;%define cols rcx
;%define filas rdx
%define filas rcx
%define cols rdx


section .text
;void temperature_asm(unsigned char *src,
;              unsigned char *dst,
;              int filas,
;              int cols,
;              int src_row_size,
;              int dst_row_size);

temperature_asm:

;rdi = unsigned char *src,
;rsi = unsigned char *dst,
;rdx = int filas,
;rcx = int cols,
;r8 = int src_row_size
;r9 = int dst_row_size

push rbp
mov rbp, rsp
push r12
push r13
push r14
push r15

xor j,j
xor i,i

pxor xmm2, xmm2
pxor xmm3, xmm3

xor rax, rax
mov r8d, r8d
mov r9d, r9d
mov edx, edx
mov ecx, ecx

lea cols, [cols + 2*cols]

.CicloFilas:

	cmp i, filas
	je .fin
	xor j,j
	mov r14, rsi 		;r14: principio de fila, matriz destino.
	mov r15, rdi 		;r15: principio de fila, matriz fuente.

.CicloColumnas:

	cmp j, cols
	je .FinColumnas
	add j, 16
	cmp j, cols
	jg .CasoPadding

	sub j, 16
	movdqu xmm0, [rdi]
	.Procesar:
	pshufb xmm0, [mask]
	movdqu xmm2, xmm0
	movdqu xmm3, xmm0
	pxor xmm0, xmm0
	punpcklbw xmm3, xmm0		;xmm3 = |00|0r|0g|0b|00|0r|0g|0b|
	punpckhbw xmm2, xmm0		;xmm2 = |00|0r|0g|0b|00|0r|0g|0b|
	phaddw xmm3, xmm3
	phaddw xmm3, xmm3 		;xmm3 = |*|*|*|*|*|*|r+g+b|r+g+b|
	phaddw xmm2, xmm2
	phaddw xmm2, xmm2 		;xmm2 = |*|*|*|*|*|*|r+g+b|r+g+b|
	pand xmm3, [borrarfruta]
	pand xmm2, [borrarfruta]
	pslldq xmm2, 4
	paddusw xmm2, xmm3 		;xmm2 = |0|0|0|0|r+g+b|r+g+b|r+g+b|r+g+b|
	pxor xmm7, xmm7
	punpcklwd xmm2, xmm7 		;xmm2 = |00 r+g+b|00 r+g+b|00 r+g+b|00 r+g+b|
	movdqu xmm7, [tres] 		;xmm7 = |3|3|3|3|
	cvtdq2ps xmm7, xmm7 		;xmm7 = float(xmm7)
	cvtdq2ps xmm2, xmm2 		;xmm2 = float(xmm2)
	divps xmm2, xmm7 		;xmm2 = |suma1/3|suma2/3|suma3/3|suma4/3|
	cvttps2dq xmm2, xmm2 		;int(xmm2)

	;primer caso:
	movdqu xmm10, [mask32]
	pcmpgtd xmm10, xmm2 		;t < 32, resultado en xmm10

	;segundo caso:
	movdqu xmm13, xmm2 		;xmm13 = |suma1/3|suma2/3|suma3/3|suma4/3|
	movdqu xmm14, xmm2 		;xmm14 = |suma1/3|suma2/3|suma3/3|suma4/3|
	movdqu xmm11, [mask32]
	pcmpeqd xmm11, xmm13 		;xmm13 == 32, resultado en xmm11
	pcmpgtd xmm13, [mask32]		;xmm13 > 32, resultado en xmm13
	movdqu xmm12, [mask96]
	pcmpgtd xmm12, xmm14 		;xmm14 < 96, resultado en xmm12
	por xmm13, xmm11 		;xmm13: >= 32
	pand xmm13, xmm12 		;32<= t < 96, resultado en xmm13

	;tercer caso:
	movdqu xmm4, xmm2              	;xmm4 = |suma1/3|suma2/3|suma3/3|suma4/3|
	movdqu xmm5, xmm2              	;xmm5 = |suma1/3|suma2/3|suma3/3|suma4/3|
	movdqu xmm6, [mask160]        	;xmm6 = |160|160|160|160|
	pcmpeqd xmm4, [mask96] 		;xmm4: t == 96
	pcmpgtd xmm5, [mask96] 		;xmm5: t > 96
	pcmpgtd xmm6, xmm2 		;xmm6: t < 160
	por xmm4,xmm5 			;xmm4: 96<=t
	pand xmm4, xmm6 		;xmm4: 96<=t<160

	;cuarto caso:
	movdqu xmm7, xmm2 		;xmm7 = |suma1/3|suma2/3|suma3/3|suma4/3|
	movdqu xmm8, xmm2 		;xmm8 = |suma1/3|suma2/3|suma3/3|suma4/3|
	movdqu xmm9, [mask224] 		;xmm9 = |224|224|224|224|
	pcmpeqd xmm7, [mask160] 	;xmm7: t == 160
	pcmpgtd xmm8, [mask160] 	;xmm8: t > 160
	pcmpgtd xmm9, xmm2 		;xmm9: t < 224
	por xmm7, xmm8 			;xmm7: 160<= t
	pand xmm7, xmm9 		;xmm7: 160<=t<224

	;quinto caso:
	pxor xmm1, xmm1	 		;xmm1 es el 'en otro caso'
	por xmm1, xmm7
	por xmm1, xmm4
	por xmm1, xmm13
	por xmm1, xmm10
	pcmpeqd xmm8,xmm8 		;xmm8 = 0xFF...
	pxor xmm1, xmm8 		;xmm1: si no

	;en este punto, xmm10 tiene la máscara para el caso 1, xmm13 del 2, xmm4 del 3, xmm7 del 4 y xmm1 del 5.

	;caso 1

	movdqu xmm3, xmm2 		;xmm3 tiene una copia de las temperaturas
	paddd xmm3, xmm3
	paddd xmm3, xmm3 		;multiplico por 4 cada temperatura
	paddd xmm3, [mask128] 		;les sumo 128
	pand xmm3, xmm10 		;filtro las que no van
	packusdw xmm3, xmm3
	packuswb xmm3, xmm3 		;empaqueto dos veces, hasta llegar a tener bytes
	pshufb xmm3, [mask_temp1] 	;shuffleo con la mascara que le corresponde al caso
	movdqu xmm10, xmm3 		;xmm10 tiene el primer caso procesado.

	;caso 2

	movdqu xmm3, xmm2		;xmm3 tiene una copia de las temperaturas
	psubd xmm3, [mask32] 		;les resto 32
	paddd xmm3, xmm3
	paddd xmm3, xmm3 		;multiplico (t-32) por 4.
	pand xmm3, xmm13 		;filtro los caso que no van
	packusdw xmm3, xmm3
	packuswb xmm3, xmm3 		;empaqueto hasta llegar a bytes
	pshufb xmm3, [mask_temp2] 	;shuffleo para la mascara de ese caso
	pand xmm13, [caso2] 		;filtro, para los pixeles que corresponde para el caso, la información que falta
	paddusb xmm13, xmm3 		;sumo lo que faltaba para el caso. xmm13 tiene le segundo caso procesado.

	;caso 3

	movdqu xmm3, xmm2 		;levanto las temperaturas en xmm3
	psubd xmm3, [mask96] 		;les resto 96
	paddd xmm3, xmm3
	paddd xmm3, xmm3 		;multiplico (t-96) *4
	pand xmm3, xmm4 		;filtro los casos que no van.
	packusdw xmm3, xmm3
	packuswb xmm3, xmm3 		;empaqueto hasta llegar a byte
	pshufb xmm3, [mask_temp1] 	;shuffleo igual que en el primer caso (porque justo coincide cómo shufflear)
	movdqu xmm5, xmm2 		;levanto las temperaturas en xmm5
	psubd xmm5, [mask96] 		;resto 96 a cada temperatura
	paddd xmm5, xmm5
	paddd xmm5, xmm5 		;(t-96)*4
	pand xmm5, xmm4 		;filtro los casos que no van.
	packusdw xmm5, xmm5
	packuswb xmm5, xmm5 		;empaqueto hasta llegar a byte
	pshufb xmm5, [mask_temp3] 	;shuffleo
	pand xmm4, [caso3] 		;hago un and entre los que cumplen la condición y el caso actual
	paddusb xmm4, xmm5 		;sumo (t-96)*4 donde corresponde
	psubusb xmm4, xmm3 		;resto (t-96)*4 donde corresponde

	;caso 4:

	movdqu xmm3, xmm2
	psubd xmm3, [mask160]
	paddd xmm3, xmm3
	paddd xmm3, xmm3
	pand xmm3, xmm7
	packusdw xmm3, xmm3
	packuswb xmm3, xmm3
	pshufb xmm3, [mask_temp4]
	pand xmm7, [caso4]
	psubusb xmm7, xmm3

	;caso 5:

	movdqu xmm3, xmm2
	psubd xmm3, [mask224]
	paddd xmm3, xmm3
	paddd xmm3, xmm3
	pand xmm3, xmm1
	packusdw xmm3, xmm3
	packuswb xmm3, xmm3
	pshufb xmm3, [mask_temp5]
	pand xmm1, [caso5]
	psubusb xmm1, xmm3

	pxor xmm2, xmm2 		;xmm2 = 0

	por xmm2, xmm10
	por xmm2, xmm13
	por xmm2, xmm4
	por xmm2, xmm7
	por xmm2, xmm1
	pshufb xmm2, [a43bytes] 	;xmm2 tiene la data a escribir en dst

	cmp r12, 1
	je .SegundaParte
	cmp r12, 2
	je .Unir

	movdqu [rsi], xmm2
	add rsi, 12
	add rdi, 12
	add j, 12
	jmp .CicloColumnas

	.CasoPadding:

	mov rsi, r14 			;me paro al principio de la fila (imagen destino)
	mov rdi, r15 			;me paro al principio de la fila (imagen fuente)
	;add rsi, r9 			;le sumo row_size a los dos punteros
	;add rdi, r8
	;sub rsi, padding		;les resto el ancho del padding, para posicionarme al final
	;sub rdi, padding
	add rsi, cols
	add rdi, cols
	sub rsi, 16 			;retrocedo 16 bytes, para procesar
	sub rdi, 16 			;los ultimos 5 pixeles

	movdqu xmm0, [rdi]              ;xmm0 tiene una copia de los últimos 5 de la imagen fuente
	pshufb xmm0, [mask_padd1]
	mov r12, 1
	jmp .Procesar

	;mov rsi, r14
	;mov rdi, r15
	;add rsi, r9
	;add rdi, r8
	;jmp .FinColumnas

	.SegundaParte:
	movdqu xmm15, xmm2
	pand xmm15, [padd_1]
	pslldq xmm15, 1
	mov r12, 2
	movdqu xmm0, [rdi]
	pshufb xmm0, [mask_padd2]
	jmp .Procesar

	.Unir:
	pand xmm2, [padd_2]
	pslldq xmm2, 10
	movdqu xmm0, [rsi]
	pand xmm0, [mask_dest]
	xor r12, r12
	por xmm0, xmm2
	por xmm0, xmm15
	movdqu [rsi], xmm0
	mov rsi, r14
        mov rdi, r15
        add rsi, r9
        add rdi, r8
        jmp .FinColumnas



.FinColumnas:

	add i, 1
	;cmp i, filas
	;je .fin
	jmp .CicloFilas

.fin:
pop r15
pop r14
pop r13
pop r12
pop rbp
.Final:
ret
